﻿using System;
using System.IO;
using System.Reflection;
using FireStarter.Base.BusinessObjectMerger;
using Firestarter.DB.Schema.BO;
using Firestarter.DB.Schema.Test.BO.TestUtils;
using Firestarter.DB_DomainModel.Logic;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using FireStarterModeller.Logic.FsStartLoading;
using Habanero.Base;
using Habanero.BO;
using NUnit.Framework;

namespace FireStarterModeller.Test.Logic
{
    [TestFixture]
    public class TestAcceptFsStartLoading
    {
// ReSharper disable InconsistentNaming
        private const string STANDARD_PROJECT_FILENAME = "standardProject.fstart";
// ReSharper restore InconsistentNaming

        [TestFixtureSetUp]
        public void SetupFixture()
        {
            TestUtilsLogic.SetupFixture();
        }

        [TestFixtureTearDown]
        public void TearDownFixture()
        {
            if (File.Exists(GetFsStartLoadingTempDirectory() + STANDARD_PROJECT_FILENAME))
            {
                File.Delete(GetFsStartLoadingTempDirectory() + STANDARD_PROJECT_FILENAME);
            }

        }


        [SetUp]
        public void SetupTest()
        {
            TestUtilsLogic.SetupTest();

        }

        // ReSharper disable InconsistentNaming

        [Test]
        public void Test_CanLoad_fsart_FromMemoryResourceFile()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            FMDataStore.Reset();
            //---------------Execute Test ----------------------
            Assert.IsEmpty(FMDataStore.FMDataStoreInMemory.AllObjects);
            FMDataStore.FMDataStoreInMemory.AllObjects = FsStartLoaderSpy.CallLoadDataStore(new MemoryStream(ResourcesForTesting.standardCodeTemplateLibrary));
            //---------------Test Result -----------------------
            Assert.IsNotNull(FMDataStore.FMDataStoreInMemory.AllObjects);
            Assert.AreEqual(1, FMDataStore.FMDataStoreInMemory.AllObjects.Count);
        }
        /// <summary>
        /// Create a standard fstart in the temp directory. Load the standard fsstart from the temp directory.
        /// Create a standard solution. Compare loaded and standard solutions.
        /// If these fail then the Comparison of the two solutins is not working and the CompareBusinessObjects must
        /// be investigated.
        /// </summary>
        [Test]
        public void Test_CreateSaveStandardProject_LoadProject_AndCompareToStandardProject()
        {
            //---------------Set up test pack-------------------
            DataStoreInMemory dataStoreInMemory = CreateInMemoryDataAccessor();
            
            DMSolution originalSolution = GetStandardSolutionWithTestData();

            SaveDataStoreToTempFstart(dataStoreInMemory, STANDARD_PROJECT_FILENAME);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(originalSolution);
            //---------------Execute Test ----------------------

            var newDataStore = LoadDataStoreFromTempFstart(STANDARD_PROJECT_FILENAME);
            var loadedSolution = newDataStore.Find<DMSolution>(originalSolution.ID);

            //---------------Test Result -----------------------
            Assert.IsNotNull(loadedSolution);
            Assert.AreEqual(1, loadedSolution.Assemblies.Count, "Solution should have one assembly");
            var mergeBO = MergeableBORegistry.Instance.Resolve<DMSolution>();
            var areEqual = mergeBO.CompareBusinessObjects(originalSolution, loadedSolution).AreEqual;
            Assert.IsTrue(areEqual);
        }
        /// <summary>
        /// Load a standard fsstart from the resource.
        /// Create a standard Solution.
        /// Compare the loaded fsstart to the standard solution.
        /// 
        /// This is testing that nothing has changed with the loading of any and all business objects.
        /// If this test fails and the above test fails then something has changed with the Comparing of 
        /// business objects.
        /// </summary>
        [Test]
        public void Test_LoadDataStoreFromFile_AndCompareToCreatedStandardProject_ShouldBeSame()
        {
            //---------------Set up test pack-------------------
            //There is no setup required for this project since the Files are being read from a resource.
            //TODO andrew 27 Oct 2010: Should change to read from a resource.
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            var loadedDataStore = LoadDataStoreFromFstart(STANDARD_PROJECT_FILENAME);
            //---------------Test Result -----------------------
            BORegistry.DataAccessor = new NonValidatingDataAccessorInMemory(loadedDataStore);
            Criteria criteria = new Criteria("SolutionName", Criteria.ComparisonOp.Equals, "StdSolutionName");
            var loadedSolution = loadedDataStore.Find<DMSolution>(criteria);


            Assert.Greater(loadedDataStore.AllObjects.Count, 30, "There should be more than one object in the Datastore");
            Assert.IsNotNull(loadedSolution);
            Assert.AreEqual(1, loadedSolution.Assemblies.Count, "Solution should have one assembly");
            DMSolution createdSolution = GetStandardSolutionWithTestData();
            
            //Assert.IsNotNull(loadedSolution);
            var mergeBO = MergeableBORegistry.Instance.Resolve<DMSolution>();
            var areEqual = mergeBO.CompareBusinessObjects(createdSolution, loadedSolution).AreEqual;
            Assert.IsTrue(areEqual);
        }

        // ReSharper restore InconsistentNaming
        private static DMSolution GetStandardSolutionWithTestData()
        {
            var solution = new SolutionCreator().CreateSolution();
            solution.SolutionName = "StdSolutionName";
            solution.Save();
            Assert.IsNotNull(solution.DefaultAssembly);
            Assert.AreEqual(1, solution.Assemblies.Count);
            var relatedTable = new DBTable("RelatedTable");
            var relatedTableBuilder = new DBTableBuilder(relatedTable);
            relatedTableBuilder.AddPrimaryKeyColumn("RelatedTableID");


            var dbTableBuilder = new DBTableBuilder(new DBTable("Table"));
            dbTableBuilder.AddColumnWithAllPropsSet();
            dbTableBuilder.AddColumn("BOLookupList");
            dbTableBuilder.AddColumn("DBLookupList");
            dbTableBuilder.AddForeignKey("FKName", relatedTable);
            dbTableBuilder.AddPrimaryKeyColumn("TableID");
            dbTableBuilder.AddUniqueKeyColumn("UCColumn");

            dbTableBuilder.AddAutoIncrementingColumn();

            var dbViewBuilder = new DbViewBuilder(new DBView("DBView"));
            dbViewBuilder.AddColumn("SomeViewColumn");


            var database = TestUtilsDBDatabase.CreateUnsavedValidDBDatabase();
            database.Tables.Add(relatedTable);
            database.Tables.Add(dbTableBuilder.Table);
            database.Views.Add(dbViewBuilder.View);

            database.Save();


            Assert.AreEqual(2, database.Tables.Count);
            Assert.AreEqual(1, database.Views.Count);
            new SolutionTraverser().MarkChangeTypeAdd(database);

            IDBChangesImporter dbChangesImporter = GetDBChangesImporter(solution);

            dbChangesImporter.ImportDBChanges(database, solution);

            
            Assert.Greater(solution.AllClasses.Count, 1, "There should be some classes created");

            DMClass dmClass = solution.FindClassByMappedTableName("Table");
            Assert.IsNotNull(dmClass);
            DMProperty dmProperty1 = dmClass.FindBOPropertyByColumnName("DBColumnName");
            Assert.IsNotNull(dmProperty1);
            AssertRulesAreSetOnProperty(dmProperty1);

            SetupSimpleLookupList(dmProperty1);
            SetupBOLookupList(dmClass);
            SetupDBLookupList(dmClass);

            solution.Save();

            UIViewCreator uiViewCreator = new UIViewCreator();
            Assert.GreaterOrEqual(dmClass.Properties.Count, 1);
            Assert.GreaterOrEqual(dmClass.Properties.Count, 1);
            UIView uiView = uiViewCreator.CreateUIView(dmClass);


            Assert.IsNotNull(uiView);
            Assert.IsNotNull(uiView.Class);
            Assert.AreEqual(1, dmClass.UIViews.Count);

            //----------------Verify BOEditor Created Correctly---------
            UIFormInfo formInfo = uiView.UIFormInfo;
            Assert.IsNotNull(formInfo);
            Assert.GreaterOrEqual(formInfo.UIFields.Count, 1);
            CreateUIParamenter(formInfo);
            Assert.GreaterOrEqual(formInfo.UITabs.Count, 1);
            Assert.GreaterOrEqual(formInfo.UITabs[0].UIColumnLayouts.Count, 1);

            //---------------Verify GridFilter Created Correctly-------
            UIGridFilter gridFilter = uiView.UIGridInfo.UIGridFilter;
            Assert.IsNotNull(gridFilter);
            Assert.GreaterOrEqual(gridFilter.UIGridFilterProps.Count, 1);

            //---------------Verify GridInfo Created Correctly---------
            UIGridInfo gridInfo = uiView.UIGridInfo;
            Assert.IsNotNull(gridInfo);
            Assert.GreaterOrEqual(gridInfo.UIColumns.Count, 1);
            solution.Save();
            return solution;
        }

        private static DataStoreInMemory LoadDataStoreFromTempFstart(string fileName)
        {
            var loadDataStoreFromFile = CreateFstartLoader().LoadDataStoreFromFile(GetFsStartLoadingTempDirectory() + fileName);
            return new DataStoreInMemory { AllObjects = loadDataStoreFromFile };
        }
        private static DataStoreInMemory LoadDataStoreFromFstart(string fileName)
        {
            var loadDataStoreFromFile = CreateFstartLoader().LoadDataStoreFromFile(GetFsStartLoadingDirectory() + fileName);
            return new DataStoreInMemory { AllObjects = loadDataStoreFromFile };
        }

        private static void SaveDataStoreToTempFstart(DataStoreInMemory dataStoreInMemory, string fileName)
        {
            var fsStartLoader = CreateFstartLoader();
            fsStartLoader.SaveDataStoreToFile(dataStoreInMemory, GetFsStartLoadingTempDirectory() + fileName);
        }
        private static void SaveDataStoreToFstart(DataStoreInMemory dataStoreInMemory, string fileName)
        {
            var fsStartLoader = CreateFstartLoader();
            fsStartLoader.SaveDataStoreToFile(dataStoreInMemory, GetFsStartLoadingDirectory() + fileName);
        }

        private static FsStartLoader CreateFstartLoader()
        {
            return new FsStartLoader();
        }

        private static DataStoreInMemory CreateInMemoryDataAccessor()
        {
            var dataStoreInMemory = new DataStoreInMemory();
            BORegistry.DataAccessor = new NonValidatingDataAccessorInMemory(dataStoreInMemory);
            return dataStoreInMemory;
        }

        private static void SetupDBLookupList(DMClass dmClass)
        {
            DMProperty dmProperty = dmClass.FindBOPropertyByColumnName("DBLookupList");
            Assert.IsNotNull(dmProperty);
            dmProperty.LookupList = TestUtilsDMLookupListDatabase.CreateStandardDMLookupListDB();
        }

        private static void SetupBOLookupList(DMClass dmClass)
        {
            DMProperty dmProperty = dmClass.FindBOPropertyByColumnName("BOLookupList");
            Assert.IsNotNull(dmProperty);
            dmProperty.LookupList = TestUtilsDMLookupLisBusinessObject.CreateStandardDMLookupListBO();
        }

        private static void AssertRulesAreSetOnProperty(DMProperty dmProperty1)
        {
            Assert.IsNotNull(dmProperty1.DefaultPropRule);
            Assert.GreaterOrEqual(dmProperty1.DefaultPropRule.PropRuleParameters.Count, 1);
        }

        private static void SetupSimpleLookupList(DMProperty dmProperty)
        {
            dmProperty.LookupList = TestUtilsDMLookupListSimple.CreateUnsavedStandardDMLookupListSimple(dmProperty);
        }

        private static void CreateUIParamenter(UIFormInfo formInfo)
        {
            UIParameter parameter = formInfo.UIFields[0].UIParameters.CreateBusinessObject();
            parameter.Name = "UIParameterName";
            parameter.Value = "UIParameterValue";
        }

        private static IDBChangesImporter GetDBChangesImporter(DMSolution dmSolution)
        {
            DBToDMImporterFactory dbToDMImporterFactory = new DBToDMImporterFactory(new DBTypeToDMPropertyTypeMapper(new PropertyTypeStorer(dmSolution)), new RelationshipNameGenerator());
            return dbToDMImporterFactory.CreateDBChangesImporter();
        }


        #region Get Directory

        private static string AssemblyDirectory
        {
            get
            {
                string codeBase = Assembly.GetExecutingAssembly().CodeBase;
                UriBuilder uri = new UriBuilder(codeBase);
                string path = Uri.UnescapeDataString(uri.Path);
                return Path.GetDirectoryName(path);
            }
        }

/*        private static string GetProjectDirectory()
        {
            return AssemblyDirectory.Substring(0, AssemblyDirectory.IndexOf("bin"));
        }*/
        private static string GetFsStartLoadingDirectory()
        {
            return FsStartTestindDirectory.GetFsStartLoadingDirectory();
        }


        private static string GetFsStartLoadingTempDirectory()
        {
            return FsStartTestindDirectory.GetFsStartLoadingTempDirectory();
        }

        #endregion

    }
}